//
//  NSObject+TFCore.h
//  TFFoundation
//
//  Created by TFAppleWork-Summer on 2017/3/10.
//  Copyright © 2017年 TFAppleWork-Summer. All rights reserved.
//

#import <Foundation/Foundation.h>

/**
 筛选的block

 @param selectorName 方法名字
 @return 返回是否符合条件
 */
typedef BOOL(^TFObjectPrecateBlock)(NSString * _Nonnull selectorName);

/**
 遍历属性的block

 @param propertyName 属性名字
 @param propertyTypeName 属性的类型名字
 @param propertyClass 如果属性为对象或数组时返回对应的Class
 */
typedef void(^TFPropertyEnumerateBlock)(NSString * _Nonnull propertyName, NSString * _Nonnull  propertyTypeName, Class __nullable propertyClass);

/**
 监听keypath对应的值发生变化的block

 @param obj 监听者对象
 @param oldVal 旧的值
 @param newVal 新的值
 */
typedef void(^TFObjectObserverValueChangeBlock)(__nonnull id obj, __nonnull id oldVal, __nonnull id newVal);

/**
 关联协议类型
 */
typedef NS_ENUM(NSUInteger, TFAssociationPolicy) {
    TFAssociationPolicy_assign = 0,///< assgin 方式
    TFAssociationPolicy_retain_nonatomic = 1,///<retain和nonatomic 方式
    TFAssociationPolicy_copy_nonatomic = 3,///< copy和nonatomic 方式
    TFAssociationPolicy_retain = 01401,///< retain 方式
    TFAssociationPolicy_copy = 01403,///<copy 方式
};

/**
 NSObject的快捷方法类别
 */
@interface NSObject (TFCore)

///=============================================================================
/// @name 常用类方法
///=============================================================================

/**
 获取某个类的所有方法名字

 @return NSArray<NSString *>
 */
+ (nonnull NSArray<NSString *> *)tf_getMethodNameList;

/**
 获取某个类的所有方法并根据筛选条件筛选
 
 @param predicateBlock 筛选条件块
 @return NSArray<NSString *>
 */
+ (nonnull NSArray<NSString *> *)tf_getMethodNameListWithPredicateBlock:(nullable TFObjectPrecateBlock)predicateBlock;

/**
 遍历整个属性数组
 
 @param block 遍历的block
 */
+ (void)tf_enumeratePropertyListWithBlock:(nonnull TFPropertyEnumerateBlock)block;

/**
 获取整个类的所有属性名称

 @return NSArray<NSString *>
 */
+ (nonnull NSArray<NSString *> *)tf_getPropertyNameList;

/**
 实例方法置换
 
 @param originalSel 原来的方法
 @param newSel 新的方法
 @return 置换是否成功
 */
+ (BOOL)tf_swizzleInstanceMethod:(nonnull SEL)originalSel with:(nonnull SEL)newSel;

/**
 类方法置换
 
 @param originalSel 原来的方法
 @param newSel 新的方法
 @return 置换是否成功
 */
+ (BOOL)tf_swizzleClassMethod:(nonnull SEL)originalSel with:(nonnull SEL)newSel;

/**
 获取class名称字符串

 @return NSString
 */
+ (nonnull NSString *)tf_classNameString;

/**
 获取所有的子类
 
 @return NSArray 子类数组
 */
+ (nullable NSArray<Class> *)tf_subClasses;

///=============================================================================
/// @name 常用实例方法
///=============================================================================

/**
 获取class名称字符串

 @return NSString
 */
- (nonnull NSString *)tf_classNameString;

/**
 通过设置key和value以及协议类型关联对象

 @param value 值
 @param key 键
 @param assoicationPolicy 协议类型
 */
- (void)tf_setAssociateValue:(nonnull id)value withkey:(nonnull void *)key assoicationPolicy:(TFAssociationPolicy)assoicationPolicy;

/**
 根据key获取相关联的value

 @param key 键
 @return 关联的对象
 */
- (nonnull id)tf_getAssociateValueForKey:(nonnull void *)key;

/**
 移除所有的关联对象
 */
- (void)tf_removeAssociatedValues;

/**
 根据属性名称获取属性值

 @param name 属性名称
 @return id 属性值
 */
- (nullable id)tf_propertyValueForName:(nonnull NSString *)name;

/**
 根据keyPath获取属性值

 @param keyPath 属性路径
 @return id 属性值
 */
- (nullable id)tf_propertyValueForKeyPath:(nonnull NSString *)keyPath;

/**
 根据keyPath判断两个类是否相等

 @param object 对象
 @param keyPath 路径
 @return BOOL 是否相等
 */
- (BOOL)tf_isEqualObject:(nonnull id)object withKeyPath:(nonnull NSString *)keyPath;

/**
 判断这个类的所有属性是否相等

 @param object 对象
 @return BOOL 是否相等
 */
- (BOOL)tf_isPropertiesEqualObject:(nonnull id)object;

/**
 通过keyPath和值变化的block添加监察者
 
 @param keyPath 路径
 @param block 值变化代码块
 */
- (void)tf_addObserverBlockForKeyPath:(nonnull NSString*)keyPath block:(nonnull TFObjectObserverValueChangeBlock)block;

/**
 通过keyPath移除监察者
 
 @param keyPath 路径
 */
- (void)tf_removeObserverBlocksForKeyPath:(nonnull NSString *)keyPath;

/**
 移除所有的监察者
 */
- (void)tf_removeObserverBlocks;

@end
